<template>
  <div class="d-flex flex-col gap-col-8">
    <div class="d-flex flex-col gap-col-8">
      <TagSwiper
        v-model="currentPayway"
        :items="paywayOptions"
        item-label="name"
        item-value="id"
        theme="dark"
        :show-on-mobile="true"
        :checker="(item) => item.active"
        @click="onTagClick"
      ></TagSwiper>
    </div>
    <div v-if="paymentError" class="text-primary font-size-10 font-weight-500 line-height-875">{{ paymentError }}</div>
    <div v-if="isLoading" class="d-flex flex-col gap-col-8 loading">
      <div class="item"></div>
      <div class="item"></div>
    </div>
    <div v-else>
      <CardList v-if="isExistCreditCard" v-model="defaultCard" @add:card="onCardAdd"></CardList>
      <CreditCard v-if="isCreditCard" ref="componentRef" @complete="onSubmitComplete"></CreditCard>
      <PopupPayment v-if="isPopupPayment" :title="popupPayment.title">
        <template #logo>
          <img class="logo" v-if="popupPayment.image" :src="popupPayment.image" alt="" />
        </template>
      </PopupPayment>
    </div>
  </div>
</template>
<script setup>
import { computed, onActivated, onDeactivated, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useAppStore } from '@/store/app'
import { useCreditCardStore } from '@/store/credit-card'
import { usePopupDialogStore } from '@/store/popup-dialog'
import { $t, locale } from '@/i18n'
import { upperSnackToCamel } from '@/utils/string-helper'
import TagSwiper from '@/components/common/TagSwiper.vue'
import { useConfirmData } from '@/compositions/dialog/confirm-data'
import { useExecutionLock } from '@/compositions/utils'
import { useWindow } from '@/compositions/utils/window'
import { PAYMENT_GROUP } from '@/constant/payment'
import CardList from './CardList.vue'
import PopupPayment from './PopupPayment.vue'
import CreditCard from './creditCard.vue'

const appStore = useAppStore()
const { allPayments, appConfig } = storeToRefs(appStore)
const { syncAllPaymentConfig } = appStore

const paymentCondition = (groupId) => allPayments.value.find((p) => p.payment_type === groupId)
const activeCondition = (groupId) => {
  const conditionItem = paymentCondition(groupId)
  if (!conditionItem) return false
  return amount.value > conditionItem.min_money && amount.value < conditionItem.max_money
}

const paywayOptions = computed(() => {
  const EMBED_STRIPE = 78
  const POPUP_STRIPE = 0

  const options = [
    {
      type: PAYMENT_GROUP.CREDIT_CARD,
      id: EMBED_STRIPE, // 但不用傳遞所以寫死
      name: $t('payment.options.bankCard'),
      active: true,
    },
  ]

  /** Stripe 其他支付方式，預設開啟 */
  const other = {
    type: PAYMENT_GROUP.OTHER,
    id: POPUP_STRIPE, // 只有 happy 金流要用 pay_type_id，丁滿說傳 0 就好
    name: $t('payment.options.other'),
    active: true,
  }

  if (appConfig.value.multi_payment_lang.includes(locale.value)) {
    const __arr = []

    Object.entries(PAYMENT_GROUP).forEach(([key, value], index) => {
      const payment = paymentCondition(value)

      // 後端沒返回 payment_type 或是 pay_type_id = 0 (代表語系同步有問題或是前端語系被篡改) 的話就不顯示
      if (!payment || payment?.pay_type_id === POPUP_STRIPE) return

      __arr.push({
        type: value,
        id: payment?.pay_type_id ?? null,
        name: $t(`payment.options.${upperSnackToCamel(key)}`),
        active: activeCondition(value),
        // 依照 PAYMENT_GROUP 的順序排列
        sort: index,
      })
    })

    // 組裝除了信用卡外的支付方式，再依照 sort 升冪排序, partition 分成 active 和 inactive
    // const steps = flow(sortBy(['sort']), partition('active'))
    // const [activePayments, inactivePayments] = steps(__arr)
    __arr.sort((a, b) => a.sort - b.sort)
    const { active: activePayments, inactive: inactivePayments } = __arr.reduce(
      (a, c) => {
        if (c.active) {
          a.active.push(c)
        } else {
          a.inactive.push(c)
        }
        return a
      },
      { active: [], inactive: [] },
    )

    return options.concat(activePayments, [other], inactivePayments)
  } else {
    options.push(other)
    return options
  }
})

// 直接寫死預設用信用卡
const currentPayway = ref(78)
const currentOption = computed(() => paywayOptions.value.find((item) => item.id === currentPayway.value))

const { getPrevInputData } = usePopupDialogStore()
const { content } = storeToRefs(usePopupDialogStore())

const creditCardStore = useCreditCardStore()
const { getCreditCardList } = creditCardStore
const { creditCardList } = storeToRefs(creditCardStore)

const defaultCardExists = computed(() => creditCardList.value.length > 0)
const defaultCard = ref(null)

const isAddCard = ref(false)
const { backCallback } = storeToRefs(usePopupDialogStore())
const clearBackCallback = (params = null) => {
  isAddCard.value = false
  backCallback.value = null
  if (params) return params
}
const onCardAdd = () => {
  isAddCard.value = true
  backCallback.value = clearBackCallback
}
const isExistCreditCard = computed(
  () => currentOption.value.type === PAYMENT_GROUP.CREDIT_CARD && defaultCardExists.value && !isAddCard.value,
)
const isCreditCard = computed(
  () => (currentOption.value.type === PAYMENT_GROUP.CREDIT_CARD && !defaultCardExists.value) || isAddCard.value,
)

const popupPayments = Object.values(PAYMENT_GROUP).filter((value) => value !== PAYMENT_GROUP.CREDIT_CARD)
const popupPaymentMap = {
  [PAYMENT_GROUP.ALI_PAY]: { title: 'payment.aliPay.title', image: '/images/payment/ali-pay.png' },
  [PAYMENT_GROUP.UNION_PAY]: { title: 'payment.unionPay.title', image: '/images/payment/union-pay.png' },
  [PAYMENT_GROUP.PAYPAL]: { title: 'payment.paypal.title', image: '/images/payment/paypal.png' },
  [PAYMENT_GROUP.LINE_PAY]: { title: 'payment.linePay.title', image: '/images/payment/line-pay.png' },
  [PAYMENT_GROUP.OTHER]: { title: 'payment.other.title', image: '/images/payment/other-larger.png' },
  [PAYMENT_GROUP.USDT]: { title: 'payment.usdt.title', image: '/images/payment/usdt.png' },
}
const isPopupPayment = computed(() => popupPayments.includes(currentOption.value.type))
const popupPayment = computed(() => popupPaymentMap[currentOption.value.type])

const amount = computed(() => Number(content.value?.amount || getPrevInputData()?.amount))

const { disabled: isLoading, onExecute } = useExecutionLock()
onActivated(async () => {
  await onExecute(async () => {
    await getCreditCardList()
    await syncAllPaymentConfig()
    defaultCard.value = creditCardList.value.find((card) => card.is_default) || creditCardList.value[0]
  })
})

// 卸載時重置狀態
onDeactivated(() => {
  currentPayway.value = 78
  paymentError.value = ''
  clearBackCallback()
})

const componentRef = ref(null)

const isComplete = ref(false)
const submitResult = ref(false)
const intent = ref(null)

function onSubmitComplete({ status, intent: _intent }) {
  submitResult.value = status
  _intent && (intent.value = _intent)
  isComplete.value = true
}

// 輪詢 isComplete 是否為 true，取決於 CreditCard 組件的 complete 事件，再決定要返回 false 或數據
function recallComplete() {
  return new Promise((resolve) => {
    const interval = setInterval(() => {
      if (isComplete.value) {
        clearInterval(interval)
        resolve(submitResult.value)
      }
    }, 500)
  }).then((r) => (r ? { intent: intent.value } : false))
}

useConfirmData(async () => {
  if (!checkAmount(currentOption.value)) return false

  try {
    if (isCreditCard.value) {
      isComplete.value = false
      const submitBtn = componentRef.value.$el.querySelector('#payment-submit-btn')
      submitBtn.click()
      return await recallComplete()
    } else if (isExistCreditCard.value) {
      if (defaultCard.value.is_ban) return false
      return { paymentMethod: defaultCard.value.id }
    } else {
      const { openWindow } = useWindow()
      return {
        payway: currentPayway.value,
        newWindow: openWindow(),
      }
    }
  } catch (e) {
    return false
  }
})

const paymentError = ref('')

const onTagClick = (item) => {
  clearBackCallback()
  checkAmount(item)
}

function checkAmount(item) {
  if (item.type === PAYMENT_GROUP.CREDIT_CARD || item.type === PAYMENT_GROUP.OTHER) {
    paymentError.value = ''
    return true
  }

  const payment = allPayments.value.find((p) => p.pay_type_id === item.id)
  if (!payment) throw new Error('payment not found')

  if (amount.value > payment.max_money || amount.value < payment.min_money) {
    paymentError.value = $t('payment.error.amountRange', {
      payment: item.name,
      min: payment.min_money,
      max: payment.max_money,
    })
    return false
  }
  paymentError.value = ''
  return true
}
</script>
<style scoped lang="scss">
.base {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 20px;
  font-size: 20px;
}

@import '@/assets/styles/loading-skeleton.scss';

.loading {
  width: 100%;

  .item {
    height: 2.5rem;
    border-radius: 0.625rem;
    @include loading-skeleton;
  }
}

.logo {
  width: 2.5rem;
  height: 2.5rem;
  object-fit: contain;
}
</style>
